package com.quectel.dms.controller.zlm;

import com.google.common.base.Preconditions;
import com.quectel.constant.sys.SysConfigKeyConstants;
import com.quectel.core.module.device.dto.DeviceDto;
import com.quectel.core.module.device.service.DeviceService;
import com.quectel.dms.controller.BaseController;
import com.quectel.sdk.zlm.ZlmMediaKitClientBuilder;
import com.quectel.sdk.zlm.basemodel.ZlmAccessConfCls;
import com.quectel.sdk.zlm.basemodel.hook.*;
import com.quectel.sdk.zlm.basemodel.vo.AddFFmpegSourceResp;
import com.quectel.sdk.zlm.common.ZlmClient;
import com.quectel.sdk.zlm.constant.ZlmMediaKitConstants;
import com.quectel.sys.module.sys.service.SysConfigService;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.http.HttpRestUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 在这里编写说明
 *
 * @author: rananxin
 * @email: ryan.ran@quectel.com
 * @date: 2023-01-06 13:21:00
 */
@RestController
@RequestMapping("zlm/hook")
@Tag(name = "ZLMHookController")
@Slf4j
public class ZLMHookController extends BaseController {

    private static final HttpRestUtils HTTP_REST_UTILS = HttpRestUtils.getDefaultInstance();

    @DubboReference
    private DeviceService deviceService;
    @DubboReference
    private SysConfigService sysConfigService;

    @PostMapping("onPlay")
    public HookOnPlayResp onPlay(@RequestBody HookOnPlayReq hookOnPlayReq) {
        logger.info("onPlay: 请求参数：{}", hookOnPlayReq);
        return HookOnPlayResp.ok();
    }

    @PostMapping("onStreamNoneReader")
    public HookOnStreamNoneReaderResp onStreamNoneReader(@RequestBody HookOnStreamNoneReaderReq hookOnStreamNoneReaderReq) {
        logger.info("onStreamNoneReader: 请求参数：{}", hookOnStreamNoneReaderReq);
        return HookOnStreamNoneReaderResp.ok();
    }

    @PostMapping("onRtspRealm")
    public HookOnRtspRealmResp onRtspRealm(@RequestBody HookOnRtspRealmReq hookOnRtspRealmReq) {
        logger.info("onRtspRealm: 请求参数：{}", hookOnRtspRealmReq);
        return HookOnRtspRealmResp.noExecAuth();
    }

    @PostMapping("onStreamNotFound")
    public HookOnStreamNotFoundResp onStreamNotFound(@RequestBody HookOnStreamNotFoundReq hookOnStreamNotFoundReq) throws DecoderException {
        logger.info("onStreamNotFound: 请求参数：{}", hookOnStreamNotFoundReq);

        String deviceId = hookOnStreamNotFoundReq.getStream();
        String mediaServerId = hookOnStreamNotFoundReq.getMediaServerId();
        if (StringUtils.isBlank(deviceId)
                || StringUtils.isBlank(mediaServerId)
                || ZlmMediaKitConstants.DEFAULT_SERVER_ID.equals(mediaServerId)) {
            // 非法参数不予推流
            return HookOnStreamNotFoundResp.ok();
        }

        String configValueByKey = sysConfigService.getConfigValueByKey(SysConfigKeyConstants.ZLM_ACCESS_CONF);
        DeviceDto deviceDto = deviceService.selectCacheById(Long.valueOf(deviceId));
        if (deviceDto == null
                || StringUtils.isBlank(configValueByKey)
                || CollectionUtils.isEmpty(JacksonUtils.parseArray(configValueByKey, ZlmAccessConfCls.class))) {
            logger.warn("onStreamNotFound：启动推流器失败 设备不存在获zlm配置错误");
            return HookOnStreamNotFoundResp.ok();
        }

        List<ZlmAccessConfCls> zlmAccessConfCls = JacksonUtils
                .parseArray(configValueByKey, ZlmAccessConfCls.class);

        Set<Object> objects = ConcurrentHashMap.newKeySet();
        Optional<ZlmAccessConfCls> first = zlmAccessConfCls.stream()
                .filter(o -> objects.add(o.getHost()))
                .filter(o -> mediaServerId.equals(o.getHost()))
                .findFirst();
        if (!first.isPresent()) {
            logger.warn("onStreamNotFound：启动推流器失败 mediaServerId错误");
            return HookOnStreamNotFoundResp.ok();
        }
        ZlmAccessConfCls goalNode = first.get();
        ZlmClient zlmClient = ZlmMediaKitClientBuilder.builder()
                .host(goalNode.getHost())
                .secret(goalNode.getSecret())
                .build();

        // 获的源流，本来可以hook params代入，这里重新获取下
//        AbstractIntelligentMonitorAccessor intelligentMonitorAccessor = AccessorUtils.getIntelligentMonitorAccessor(deviceDto.getDeviceType());
//        Preconditions.checkNotNull(intelligentMonitorAccessor);
//        StreamResp stream = intelligentMonitorAccessor.getStreamUrl(deviceDto);

        String params = hookOnStreamNotFoundReq.getParams();
        Preconditions.checkArgument(params != null, "Illegal request");

        String streamUrl = new String(Hex.decodeHex(params));

        AddFFmpegSourceResp addFfmpegSourceResp = zlmClient.addFFmpegSource(deviceId, streamUrl);
        if (ZlmMediaKitConstants.RespCodeEnum.SUCCESS_CODE.getCode() == addFfmpegSourceResp.getCode()) {
            logger.info("onStreamNotFound：启动推流器成功 key {} originStream {}", deviceId, streamUrl);
        }
        return HookOnStreamNotFoundResp.ok();
    }
}
